From 38f226b5cef1660c7a7f465528befbd65ab944a5 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 19 Nov 2016 20:38:22 +0100 Subject: [PATCH] render: Propagate snapshot drawing to box shadows This decouples actual background drawing from shadow drawing in the snapshot case. We also now create seperate nodes for shadows vs for backgrounds. --- gtk/gtkcssshadowsvalue.c | 36 +++++++++++++++++++++ gtk/gtkcssshadowsvalueprivate.h | 6 ++++ gtk/gtkcssshadowvalue.c | 53 +++++++++++++++++++++++++++++++ gtk/gtkcssshadowvalueprivate.h | 8 ++++- gtk/gtkrenderbackground.c | 56 +++++++++++++++++++++++---------- 5 files changed, 141 insertions(+), 18 deletions(-) diff --git a/gtk/gtkcssshadowsvalue.c b/gtk/gtkcssshadowsvalue.c index e2be207ad6..18381553ac 100644 --- a/gtk/gtkcssshadowsvalue.c +++ b/gtk/gtkcssshadowsvalue.c @@ -315,6 +315,42 @@ _gtk_css_shadows_value_paint_box (const GtkCssValue *shadows, } } +void +gtk_css_shadows_value_snapshot_outset (const GtkCssValue *shadows, + GtkSnapshot *snapshot, + const GtkRoundedBox *border_box) +{ + guint i; + + g_return_if_fail (shadows->class == >K_CSS_VALUE_SHADOWS); + + for (i = 0; i < shadows->len; i++) + { + if (_gtk_css_shadow_value_get_inset (shadows->values[i])) + continue; + + gtk_css_shadow_value_snapshot_outset (shadows->values[i], snapshot, border_box); + } +} + +void +gtk_css_shadows_value_snapshot_inset (const GtkCssValue *shadows, + GtkSnapshot *snapshot, + const GtkRoundedBox *padding_box) +{ + guint i; + + g_return_if_fail (shadows->class == >K_CSS_VALUE_SHADOWS); + + for (i = 0; i < shadows->len; i++) + { + if (!_gtk_css_shadow_value_get_inset (shadows->values[i])) + continue; + + gtk_css_shadow_value_snapshot_inset (shadows->values[i], snapshot, padding_box); + } +} + void _gtk_css_shadows_value_get_extents (const GtkCssValue *shadows, GtkBorder *border) diff --git a/gtk/gtkcssshadowsvalueprivate.h b/gtk/gtkcssshadowsvalueprivate.h index 790e8ec308..59097400b5 100644 --- a/gtk/gtkcssshadowsvalueprivate.h +++ b/gtk/gtkcssshadowsvalueprivate.h @@ -47,6 +47,12 @@ void _gtk_css_shadows_value_paint_box (const GtkCssValue cairo_t *cr, const GtkRoundedBox *padding_box, gboolean inset); +void gtk_css_shadows_value_snapshot_outset (const GtkCssValue *shadows, + GtkSnapshot *snapshot, + const GtkRoundedBox *border_box); +void gtk_css_shadows_value_snapshot_inset (const GtkCssValue *shadows, + GtkSnapshot *snapshot, + const GtkRoundedBox *padding_box); void _gtk_css_shadows_value_get_extents (const GtkCssValue *shadows, GtkBorder *border); diff --git a/gtk/gtkcssshadowvalue.c b/gtk/gtkcssshadowvalue.c index a17b213e3d..3c7aeb93ae 100644 --- a/gtk/gtkcssshadowvalue.c +++ b/gtk/gtkcssshadowvalue.c @@ -25,6 +25,7 @@ #include "gtkcsscolorvalueprivate.h" #include "gtkcssnumbervalueprivate.h" #include "gtkcssrgbavalueprivate.h" +#include "gtksnapshot.h" #include "gtkstylecontextprivate.h" #include "gtkrenderprivate.h" #include "gtkpango.h" @@ -1019,3 +1020,55 @@ _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, cairo_restore (cr); } + +void +gtk_css_shadow_value_snapshot_outset (const GtkCssValue *shadow, + GtkSnapshot *snapshot, + const GtkRoundedBox *border_box) +{ + GtkBorder extents; + cairo_t *cr; + + g_return_if_fail (shadow->class == >K_CSS_VALUE_SHADOW); + + /* We don't need to draw invisible shadows */ + if (gtk_rgba_is_clear (_gtk_css_rgba_value_get_rgba (shadow->color))) + return; + + gtk_css_shadow_value_get_extents (shadow, &extents); + + cr = gtk_snapshot_append_cairo_node (snapshot, + &(graphene_rect_t) GRAPHENE_RECT_INIT ( + border_box->box.x - extents.left, + border_box->box.y - extents.top, + border_box->box.width + extents.left + extents.right, + border_box->box.height + extents.top + extents.bottom), + "Outset Shadow"); + _gtk_css_shadow_value_paint_box (shadow, cr, border_box); + cairo_destroy (cr); +} + +void +gtk_css_shadow_value_snapshot_inset (const GtkCssValue *shadow, + GtkSnapshot *snapshot, + const GtkRoundedBox *padding_box) +{ + cairo_t *cr; + + g_return_if_fail (shadow->class == >K_CSS_VALUE_SHADOW); + + /* We don't need to draw invisible shadows */ + if (gtk_rgba_is_clear (_gtk_css_rgba_value_get_rgba (shadow->color))) + return; + + cr = gtk_snapshot_append_cairo_node (snapshot, + &(graphene_rect_t) GRAPHENE_RECT_INIT ( + padding_box->box.x, + padding_box->box.y, + padding_box->box.width, + padding_box->box.height), + "Inset Shadow"); + _gtk_css_shadow_value_paint_box (shadow, cr, padding_box); + cairo_destroy (cr); +} + diff --git a/gtk/gtkcssshadowvalueprivate.h b/gtk/gtkcssshadowvalueprivate.h index 5b89944525..7f8c86b5ed 100644 --- a/gtk/gtkcssshadowvalueprivate.h +++ b/gtk/gtkcssshadowvalueprivate.h @@ -46,11 +46,17 @@ void _gtk_css_shadow_value_paint_layout (const GtkCssValue void _gtk_css_shadow_value_paint_icon (const GtkCssValue *shadow, cairo_t *cr); - void _gtk_css_shadow_value_paint_box (const GtkCssValue *shadow, cairo_t *cr, const GtkRoundedBox *padding_box); +void gtk_css_shadow_value_snapshot_outset (const GtkCssValue *shadow, + GtkSnapshot *snapshot, + const GtkRoundedBox *border_box); +void gtk_css_shadow_value_snapshot_inset (const GtkCssValue *shadow, + GtkSnapshot *snapshot, + const GtkRoundedBox *padding_box); + G_END_DECLS #endif /* __GTK_SHADOW_H__ */ diff --git a/gtk/gtkrenderbackground.c b/gtk/gtkrenderbackground.c index c0a7d7560e..7def6b01e1 100644 --- a/gtk/gtkrenderbackground.c +++ b/gtk/gtkrenderbackground.c @@ -302,13 +302,16 @@ _gtk_theming_background_paint_layer (GtkThemingBackground *bg, } static void -_gtk_theming_background_init_style (GtkThemingBackground *bg, - double width, - double height, - GtkJunctionSides junction) +gtk_theming_background_init (GtkThemingBackground *bg, + GtkCssStyle *style, + double width, + double height, + GtkJunctionSides junction) { GtkBorder border, padding; + bg->style = style; + border.top = _gtk_css_number_value_get (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); border.right = _gtk_css_number_value_get (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); border.bottom = _gtk_css_number_value_get (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); @@ -370,8 +373,7 @@ gtk_css_style_render_background (GtkCssStyle *style, _gtk_css_shadows_value_is_none (box_shadow)) return; - bg.style = style; - _gtk_theming_background_init_style (&bg, width, height, junction); + gtk_theming_background_init (&bg, style, width, height, junction); cairo_save (cr); cairo_translate (cr, x, y); @@ -435,14 +437,17 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, gdouble height, GtkJunctionSides junction) { + GtkThemingBackground bg; + gint idx; GtkCssValue *background_image; + GtkCssValue *blend_modes; GtkCssValue *box_shadow; const GdkRGBA *bg_color; - GtkBorder shadow; - graphene_rect_t bounds; + gint number_of_layers; cairo_t *cr; background_image = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_IMAGE); + blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE); bg_color = _gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); box_shadow = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BOX_SHADOW); @@ -453,20 +458,37 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, _gtk_css_shadows_value_is_none (box_shadow)) return; - _gtk_css_shadows_value_get_extents (box_shadow, &shadow); + gtk_theming_background_init (&bg, style, width, height, junction); - graphene_rect_init (&bounds, - - shadow.left, - - shadow.top, - ceil (width) + shadow.left + shadow.right, - ceil (height) + shadow.top + shadow.bottom); + gtk_css_shadows_value_snapshot_outset (box_shadow, + snapshot, + &bg.boxes[GTK_CSS_AREA_BORDER_BOX]); + /* + * When we have a blend mode set for the background, we must blend on a transparent + * background. GSK can't do that yet. + */ cr = gtk_snapshot_append_cairo_node (snapshot, - &bounds, - "Background"); + &(graphene_rect_t)GRAPHENE_RECT_INIT(0, 0, width, height), + "Background with blend mode"); - gtk_css_style_render_background (style, cr, 0, 0, width, height, junction); + _gtk_theming_background_paint_color (&bg, cr, bg_color, background_image); + + number_of_layers = _gtk_css_array_value_get_n_values (background_image); + + for (idx = number_of_layers - 1; idx >= 0; idx--) + { + GtkCssBlendMode blend_mode; + + blend_mode = _gtk_css_blend_mode_value_get (_gtk_css_array_value_get_nth (blend_modes, idx)); + + _gtk_theming_background_paint_layer (&bg, idx, cr, blend_mode); + } cairo_destroy (cr); + + gtk_css_shadows_value_snapshot_inset (box_shadow, + snapshot, + &bg.boxes[GTK_CSS_AREA_PADDING_BOX]); } -- 2.30.2